package com.kefu.chat.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.kefu.chat.model.*;
import com.kefu.chat.service.*;
import com.kefu.chat.util.ChatConstant;
import com.kefu.chat.vo.ChatEventMsg;
import com.kefu.sys.mapper.SysTenantMapper;
import com.kefu.sys.mapper.SysUserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

@Component
@ConditionalOnProperty(prefix = "kefu.task.execute", name = "enabled", havingValue = "true", matchIfMissing = true)
public class ChatOfflineTask {
    @Resource
    private SysTenantMapper sysTenantMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Autowired
    private ChatCacheService chatCacheService;
    @Autowired
    private ChatAdminService chatAdminService;
    @Autowired
    private ChatUserService chatUserService;
    @Autowired
    private ChatChannelService chatChannelService;
    @Autowired
    ChatReceptConfigService chatReceptConfigService;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Scheduled(initialDelayString = "#{ T(java.util.concurrent.ThreadLocalRandom).current().nextInt(60*1000) }", fixedRate = 30 * 1000)
    public void leaveOffline() {
        logger.debug("leaveOffline_start");
        List<String> tenantIdList = sysTenantMapper.selectAllId();
        for (String tenantId : tenantIdList) {
            try {
                Map<String, String> adminTimeMap = chatCacheService.getAdminPollTime(tenantId);
                if (adminTimeMap != null) {
                    for (String adminId : adminTimeMap.keySet()) {
                        if (StrUtil.isNotBlank(adminId) && Long.parseLong(adminTimeMap.get(adminId)) < System.currentTimeMillis() - 5 * 60 * 1000) {
                            logger.info("leaveOffline_admin:{},{}", adminId, adminTimeMap.get(adminId));
                            ThreadUtil.execute(() -> chatAdminService.out(adminId, ChatConstant.out_type_close));
                        }
                    }
                }
                Map<String, String> userTimeMap = chatCacheService.getUserPollTime(tenantId);
                if (userTimeMap != null) {
                    for (String userId : userTimeMap.keySet()) {
                        //判断用户轮询消息接口的最后时间，如果超过一定时间，说明用户已经离开聊天页面了，可以定时下线结束会话
                        if (StrUtil.isNotBlank(userId) && Long.parseLong(userTimeMap.get(userId)) < System.currentTimeMillis() - 60 * 1000) {
                            logger.info("leaveOffline_user:{},{}", userId, userTimeMap.get(userId));
                            ChatUser chatUser = chatCacheService.getUser(userId);
                            if (chatUser == null) {
                                chatCacheService.delUserPollTime(tenantId, userId);
                                continue;
                            }
                            ChatData chatData = chatCacheService.getData(chatUser.getSessionId());
                            //如果用户在等待坐席回复，超时时间可以放长一点，用户可能返回页面查询东西又回来
                            if (chatData != null && chatData.getUserWaitReply() == 1 && Long.parseLong(userTimeMap.get(userId)) > System.currentTimeMillis() - 2 * 60 * 1000) {
                                continue;
                            }
                            logger.info("leaveOffline_user_out:{},{}", userId, userTimeMap.get(userId));
                            ThreadUtil.execute(() -> chatUserService.out(userId, ChatConstant.out_type_close));
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        logger.debug("leaveOffline_end");
    }

    @Scheduled(initialDelayString = "#{ T(java.util.concurrent.ThreadLocalRandom).current().nextInt(60*1000) }", fixedRate = 1 * 60 * 1000)
    public void robotUserOverTime() {
        logger.debug("robotUserOverTime_start");
        List<String> tenantIdList = sysTenantMapper.selectAllId();
        for (String tenantId : tenantIdList) {
            try {
                Set<String> sessionSet = chatCacheService.getRobotSet(tenantId);
                for (String sessionId : sessionSet) {
                    ChatData chatData = chatCacheService.getData(sessionId);
                    if (chatData != null) {
                        long userTime = chatData.getUserMsgTime();
                        ChatChannel channel = chatChannelService.getFromId(chatData.getChannelId());
                        int overTime = channel != null ? channel.getUserOverTime() : 10;
                        if (overTime != 0 && userTime < System.currentTimeMillis() - (long) overTime * 60 * 1000) {
                            logger.info("robotUserOverTime_out:{},{}", chatData, overTime);
                            ThreadUtil.execute(() -> chatUserService.out(chatData.getUserId(), ChatConstant.out_type_timeout));
                        }
                    } else {
                        chatCacheService.delRobotSet(tenantId, sessionId);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        logger.debug("robotUserOverTime_end");
    }

    @Scheduled(initialDelayString = "#{ T(java.util.concurrent.ThreadLocalRandom).current().nextInt(60*1000) }", fixedRate = 20 * 1000)
    public void onlineUserOverTime() {
        logger.debug("onlineUserOverTime_start");
        List<String> adminIdList = sysUserMapper.selectAllId();
        try {
            for (String adminId : adminIdList) {
                Set<String> userSet = chatCacheService.getAdminUserSet(adminId);
                for (String userId : userSet) {
                    ChatUser chatUser = chatCacheService.getUser(userId);
                    if (chatUser != null) {
                        ChatData chatData = chatCacheService.getData(chatUser.getSessionId());
                        logger.info("onlineUserOverTime_user:{},{}", chatUser, chatData);
                        if (chatData != null) {
                            long userTime = chatData.getUserMsgTime() != 0 ? chatData.getUserMsgTime() : chatUser.getOnlineTime();
                            long adminTime = chatData.getAdminMsgTime() != 0 ? chatData.getAdminMsgTime() : chatUser.getOnlineTime();
                            ChatChannel channel = chatChannelService.getFromId(chatData.getChannelId());
                            int userOverTime = channel != null ? channel.getUserOverTime() : 5;
                            int adminTimeoutTime = channel != null ? channel.getAdminTimeoutTime() : 3;
                            long outTime = System.currentTimeMillis() - (long) userOverTime * 60 * 1000;
                            long adminTipTime = System.currentTimeMillis() - (long) adminTimeoutTime * 60 * 1000;
                            if (userTime < outTime) {
                                logger.info("onlineUserOverTime_out:{},{},{},{}", chatData, userOverTime, userTime, outTime);
                                ThreadUtil.execute(() -> chatUserService.out(chatData.getUserId(), ChatConstant.out_type_timeout));
                            } else if (userTime >= adminTime && adminTime < adminTipTime && chatData.getAdminTimeout() == 0) {
                                ThreadUtil.execute(() -> {
                                    ChatReceptConfig config = chatReceptConfigService.getConfig(adminId);
                                    if (config != null && Objects.equals(config.getAdminTimeoutFlag(), 1)) {
                                        logger.info("onlineUserOverTime_adminTimeout:{},{},{},{},{}", chatData, adminTimeoutTime, userTime, adminTime, adminTipTime);
                                        ChatEventMsg.AdminTimeout adminMsg = BeanUtil.toBean(chatData, ChatEventMsg.AdminTimeout.class);
                                        ChatAdmin chatAdmin = chatCacheService.getAdmin(adminId);
                                        chatCacheService.sendEventMsg(chatAdmin.getPollId(), adminMsg);
                                        chatData.setAdminTimeout(1);
                                        chatCacheService.setData(chatData);
                                    }
                                });
                            } else {
                                logger.info("onlineUserOverTime_not:{},{},{},{},{},{},{}", chatData, userTime, adminTime, userOverTime, adminTimeoutTime, outTime, adminTipTime);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.debug("onlineUserOverTime_end");
    }
}

